package com.eastfair.pay.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.common.dto.JYMainnoResultDTO;
import com.eastfair.common.dto.JYPaymentCollectRecordDTO;
import com.eastfair.common.req.JYReq;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.pay.api.FinanceFeign;
import com.eastfair.pay.dao.PaymentRecordMapper;
import com.eastfair.pay.dto.PaymentRecordDTO;
import com.eastfair.pay.dto.PaymentRecordPageQuery;
import com.eastfair.pay.dto.PaymentRecordSaveDTO;
import com.eastfair.pay.dto.PaymentRecordUpdateDTO;
import com.eastfair.pay.entity.CollectRecord;
import com.eastfair.pay.entity.CollectionAccount;
import com.eastfair.pay.entity.JyLog;
import com.eastfair.pay.entity.PaymentRecord;
import com.eastfair.pay.entity.TransactionOrder;
import com.eastfair.pay.enumeration.TransactionOrderOrderStatusEnum;
import com.eastfair.pay.enums.CollectStateEnum;
import com.eastfair.pay.enums.OrderStateEnum;
import com.eastfair.pay.enums.PayChannelEnum;
import com.eastfair.pay.enums.PayTypeEnum;
import com.eastfair.pay.exceptioncode.PayExceptionCode;
import com.eastfair.pay.service.CollectRecordService;
import com.eastfair.pay.service.CollectionAccountService;
import com.eastfair.pay.service.JyLogService;
import com.eastfair.pay.service.JyService;
import com.eastfair.pay.service.PaymentRecordService;
import com.eastfair.pay.service.TransactionOrderService;
import com.eastfair.pay.vo.PaymentRecordVO;
import com.eastfair.projectcore.enumeration.MenuAffiliationEnum;
import io.seata.common.util.CollectionUtils;
import io.seata.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 付款记录
 * </p>
 *
 * @author clm
 * @date 2022-06-08
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class PaymentRecordServiceImpl extends SuperServiceImpl<PaymentRecordMapper, PaymentRecord> implements PaymentRecordService {

    @Value("${com.eastfair.projectId}")
    private Long projectId;

    @Resource
    private CollectRecordService collectRecordService;
    @Resource
    private CollectionAccountService collectionAccountService;
    @Resource
    private TransactionOrderService transactionOrderService;
    @Resource
    private FinanceFeign financeService;
    @Resource
    private JyService jyService;

    @Resource
    private JyLogService jyLogService;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<PaymentRecord> modelList) {
        modelList.stream().forEach(s -> {
            s.setIsDeleted(BusinessConstant.YES);
        });
        // TODO: 2021/10/29 这里需要操作其他业务，如清空角色等
        return R.successDef();
    }

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(PaymentRecord model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        if (StrUtil.isBlank(model.getCollectState())) {
            model.setCollectState(CollectStateEnum.UN_COLLECTED.getCode());
        }
        return R.successDef();
    }

    @Override
    public void update(PaymentRecordUpdateDTO paymentRecordUpdateDTO) {
        ContextUtil.setProjectId(projectId);
        //根据付款流水号查询付款信息
        PaymentRecord record = this.getRecordByMainno(paymentRecordUpdateDTO.getMainno());
        log.info("查询付款记录成功,record={}", record);
        if (record == null) {
            throw new BizException("付款记录不存在,mainno=" + paymentRecordUpdateDTO.getMainno());
        }
        List<CollectRecord> collectRecordList = collectRecordService.queryByPaymentRecordId(record.getId());
        if (CollectionUtil.isNotEmpty(collectRecordList)) {
            throw BizException.wrap(PayExceptionCode.ALREADY_COLLECT);
        }
        PaymentRecord paymentRecord = BeanUtil.copyProperties(paymentRecordUpdateDTO, PaymentRecord.class);
        paymentRecord.setId(record.getId());
        CollectionAccount account = collectionAccountService.getAccountByName(paymentRecord.getCompanyName());
        if (account != null) {
            paymentRecord.setCompanyId(account.getId());
        }
        baseMapper.updateById(paymentRecord);
        log.info("更新付款记录成功,record={}", paymentRecord);
    }

    @Override
    public Page<PaymentRecordVO> queryPagePaymentRecord(PageParams<PaymentRecordPageQuery> params) {
        PaymentRecordPageQuery model = params.getModel();
        LambdaQueryWrapper<PaymentRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 从token中获取主场标识
        String systemScene = ContextUtil.getSystemScene();
        if (!MenuAffiliationEnum.P_PAY.eq(systemScene)) {
            // 支付系统显示所有付款记录，其他系统显示属于自己的付款记录
            if (StringUtils.isEmpty(model.getCompanyName())) {
                throw new BizException(PayExceptionCode.PAYEE_IS_EMPTY.getCode(), PayExceptionCode.PAYEE_IS_EMPTY.getMsg());
            }
            lambdaQueryWrapper.eq(PaymentRecord::getCompanyName, model.getCompanyName());
        }
        lambdaQueryWrapper.eq(!StrUtil.isBlank(model.getPayType()), PaymentRecord::getPayType, model.getPayType());
        lambdaQueryWrapper.eq(!StrUtil.isBlank(model.getCollectState()), PaymentRecord::getCollectState, model.getCollectState());
        lambdaQueryWrapper.eq(!StrUtil.isBlank(model.getMainno()), PaymentRecord::getMainno, model.getMainno());
        // 付款账号
        lambdaQueryWrapper.like(!StrUtil.isBlank(model.getBankAccountNumber()), PaymentRecord::getBankAccountNumber, model.getBankAccountNumber());
        // 付款户名
        lambdaQueryWrapper.like(!StrUtil.isBlank(model.getBankAccountName()), PaymentRecord::getBankAccountName, model.getBankAccountName());
        lambdaQueryWrapper.like(!StrUtil.isBlank(model.getBankName()), PaymentRecord::getBankName, model.getBankName());

        // 收款单位
        lambdaQueryWrapper.eq(!StrUtil.isBlank(model.getCompanyName()), PaymentRecord::getCompanyName, model.getCompanyName());
        lambdaQueryWrapper.between(model.getPayStartTime() != null && model.getPayEndTime() != null, PaymentRecord::getPayTime, model.getPayStartTime(), model.getPayEndTime());
        lambdaQueryWrapper.and(!StrUtil.isBlank(model.getKeywords()), paymentRecordLambdaQueryWrapper -> paymentRecordLambdaQueryWrapper
                .like(PaymentRecord::getBankAccountName, model.getKeywords())
                .or().like(PaymentRecord::getBankAccountNumber, model.getKeywords())
                .or().like(PaymentRecord::getBankName, model.getKeywords())
        );
        Page<PaymentRecord> paymentRecordPage = params.buildPage();
        Page<PaymentRecord> page = page(paymentRecordPage, lambdaQueryWrapper);
        Page<PaymentRecordVO> paymentRecordVOPage = ConvertUtil.convertPage(page, PaymentRecordVO.class);
        return paymentRecordVOPage;
    }

    /**
     * @param paymentRecordDTO
     * @return
     */
    @Override
    public List<PaymentRecord> queryList(PaymentRecordDTO paymentRecordDTO) {
        LambdaQueryWrapper<PaymentRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.ne(PaymentRecord::getCollectState, CollectStateEnum.IS_COLLECTED.getCode());
        lambdaQueryWrapper.like(!StrUtil.isBlank(paymentRecordDTO.getBankAccountName()), PaymentRecord::getBankAccountName, paymentRecordDTO.getBankAccountName());
        lambdaQueryWrapper.like(!StrUtil.isBlank(paymentRecordDTO.getBankAccountNumber()), PaymentRecord::getBankAccountNumber, paymentRecordDTO.getBankAccountNumber());
        return baseMapper.selectList(lambdaQueryWrapper);
    }

    /**
     * @param mainno
     * @return
     */
    @Override
    public PaymentRecord getRecordByMainno(String mainno) {
        LambdaQueryWrapper<PaymentRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PaymentRecord::getMainno, mainno);
        lambdaQueryWrapper.eq(PaymentRecord::getIsDeleted, BusinessConstant.DELETE_NO);
        return baseMapper.selectOne(lambdaQueryWrapper);
    }


    /**
     * 删除记录
     *
     * @param recordId
     */
    @Override
    public void deleteById(Long recordId) {
        List<CollectRecord> collectRecordList = collectRecordService.queryByPaymentRecordId(recordId);
        if (!CollectionUtil.isEmpty(collectRecordList)) {
            throw BizException.wrap(PayExceptionCode.ALREADY_COLLECT);
        }
        removeById(recordId);
    }

    @Override
    public Boolean settlementCollect(PaymentRecordDTO paymentRecordDTO) {
        PaymentRecord record = getById(paymentRecordDTO.getId());
        if (Objects.nonNull(record)) {
            // 获取付款金额和历史认领金额
            BigDecimal payAmount = record.getPayAmount();
            BigDecimal oldCollectAmount = record.getCollectAmount();
            // 获取本次认领金额
            BigDecimal newCollectAmount = paymentRecordDTO.getCollectAmount();
            // 判断总认领金额和付款金额的关系
            BigDecimal collectAmount = oldCollectAmount.add(newCollectAmount);
            if (payAmount.compareTo(collectAmount) == 0) {
                record.setCollectState(CollectStateEnum.IS_COLLECTED.getCode());
            } else if (payAmount.compareTo(collectAmount) > 0) {
                record.setCollectState(CollectStateEnum.PART_COLLECTED.getCode());
            }
            PaymentRecord paymentRecord = new PaymentRecord();
            paymentRecord.setId(record.getId());
            paymentRecord.setCollectState(record.getCollectState());
            paymentRecord.setCollectAmount(collectAmount);
            paymentRecord.setBusinessCode(paymentRecordDTO.getBusinessCode());
            updateById(paymentRecord);
        }
        return true;
    }

    /**
     * @param paymentRecordDTO
     * @return com.eastfair.core.base.R<java.lang.Boolean>
     * @Author clm
     * @Description //金额认领
     * @Date 15:20 2023/2/14
     * @Param [paymentRecordDTO]
     */
    @Override
    @Transactional
    public Boolean amountCollect(PaymentRecordDTO paymentRecordDTO) {
        PaymentRecord paymentRecord = getById(paymentRecordDTO.getId());
        log.info("查询付款记录成功,paymentRecord={}", paymentRecord);
        BigDecimal unCollectAmount = paymentRecord.getPayAmount().subtract(paymentRecord.getCollectAmount());
        if (paymentRecordDTO.getCollectAmount().compareTo(unCollectAmount) == 1) {
            throw new BizException("超出认领额度,unCollectAmount=" + unCollectAmount);
        }

        //查询交易订单
        TransactionOrder transactionOrder = transactionOrderService.getByOrderNum(paymentRecordDTO.getBusinessCode());
        log.info("查询交易订单成功,transactionOrder={}", transactionOrder);
        if (transactionOrder == null) {
            throw new BizException("交易订单不存在,businessCode=" + paymentRecordDTO.getBusinessCode());
        }
        // 判断认款金额和订单金额是否一致
        if (BigDecimal.ZERO.compareTo(transactionOrder.getOrderAmount().subtract(paymentRecordDTO.getCollectAmount())) != 0) {
            throw BizException.wrap(PayExceptionCode.ORDER_EXCEED_COLLECT);
        }
        //构建荆艺认款记录对象
        JYReq<JYPaymentCollectRecordDTO> jyReqestDTO = jyService.buildCollectToJy(paymentRecord, transactionOrder, paymentRecord.getCollectAmount());
        JyLog jyLog = new JyLog()
                .setMethodName("同步认款记录")
                .setTableName(transactionOrder.getClass().getName())
                .setLinkId(String.valueOf(transactionOrder.getOrderNum()))
                .setRequestParameter(JSON.toJSONString(jyReqestDTO));
        log.info("同步认款记录入参，req={}", jyReqestDTO);
        R<List<JYMainnoResultDTO>> result = financeService.sync(jyReqestDTO);
        jyLog.setResponseResults(JSON.toJSONString(result));
        log.info("同步认款记录出参，result={}", result);
        if (result != null && result.getIsSuccess()) {
            jyLog.setIsSuccess(BusinessConstant.ENABLE_YES);
            if (CollectionUtils.isNotEmpty(result.getData())) {
                //保存认款记录
                CollectRecord collectRecord = new CollectRecord();
                collectRecord.setCollectAmount(paymentRecordDTO.getCollectAmount());
                collectRecord.setCollectType(paymentRecordDTO.getCollectType());
                collectRecord.setBusinessId(paymentRecordDTO.getBusinessId());
                collectRecord.setPaymentRecordId(paymentRecordDTO.getId());
                collectRecord.setBusinessCode(paymentRecordDTO.getBusinessCode());
                collectRecord.setMainno(result.getData().get(0).getMainno());
                //保存认领记录
                collectRecordService.save(collectRecord);
                log.info("保存认款记录成功,collectRecord={}", collectRecord);
                //更新付款记录
                paymentRecord.setCollectAmount((paymentRecord.getCollectAmount() == null ? new BigDecimal(0) : paymentRecord.getCollectAmount()).add(paymentRecordDTO.getCollectAmount()));
                if (paymentRecord.getCollectAmount().compareTo(paymentRecord.getPayAmount()) == 0) {
                    paymentRecord.setCollectState(CollectStateEnum.IS_COLLECTED.getCode());
                } else {
                    paymentRecord.setCollectState(CollectStateEnum.PART_COLLECTED.getCode());
                }
                updateById(paymentRecord);
                log.info("更新付款记录成功,paymentRecord={}", paymentRecord);
                // 更新交易订单的状态
                BigDecimal sumAmount = collectRecordService.calSumAmountByOrderNum(transactionOrder.getOrderNum());
                if (transactionOrder.getOrderAmount().compareTo(sumAmount) < 0) {
                    transactionOrder.setOrderStatus(TransactionOrderOrderStatusEnum.PARTPAY);
                } else {
                    transactionOrder.setOrderStatus(TransactionOrderOrderStatusEnum.PAYED);
                    transactionOrder.setState(OrderStateEnum.COMPLETED.getCode());
                }
                transactionOrder.setPayType(PayTypeEnum.TRANSFER_ACCOUNT.getCode());
                transactionOrder.setPayChannel(PayChannelEnum.CORPORATE_TRANSGER.getCode());
                transactionOrder.setPayOrderNo(paymentRecord.getMainno());
                transactionOrderService.updateById(transactionOrder);
                log.info("更新交易订单成功,transactionOrder={}", transactionOrder);
                jyLogService.save(jyLog);
                return true;
            }
        }
        jyLogService.save(jyLog);
        throw new BizException("认款失败");
    }

    /**
     * 批量保存付款记录
     *
     * @param dtos
     * @return
     */
    @Override
    public void batchSave(List<PaymentRecordSaveDTO> dtos) {
        ContextUtil.setProjectId(projectId);
        List<CollectionAccount> collectionAccounts = collectionAccountService.list();
        Map<String, Long> map = collectionAccounts.stream().collect(Collectors.toMap(CollectionAccount::getCompanyName, CollectionAccount::getId, (key1, key2) -> key2));
        for (PaymentRecordSaveDTO dto : dtos) {
            PaymentRecord paymentRecord = BeanUtil.copyProperties(dto, PaymentRecord.class);
            paymentRecord.setCompanyId(map.get(paymentRecord.getCompanyName()));
            save(paymentRecord);
            log.info("保存付款记录成功,paymentRecord={}", paymentRecord);
        }
    }

    @Override
    public void deleteByMainno(String mainno) {
        ContextUtil.setProjectId(projectId);
        //根据付款流水号查询付款信息
        PaymentRecord record = this.getRecordByMainno(mainno);
        log.info("查询付款记录成功,mainno={},record={}", mainno, record);
        if (record == null) {
            throw new BizException("付款记录不存在,mainno=" + mainno);
        }
        deleteById(record.getId());
        log.info("删除付款记录成功");

    }
}
